package com.hyt.it.ogt.kq.service.gov.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.hyt.it.ogt.kq.service.gov.api.ks.model.UserRoomVO;
import com.hyt.it.ogt.kq.service.gov.api.ks.model.UserTimeVO;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.constant.UserRoleType;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.service.gov.mapper.TimeRoomExaminerMapper;
import com.hyt.it.ogt.kq.service.gov.model.entity.Time;
import com.hyt.it.ogt.kq.service.gov.model.entity.TimeExaminer;
import com.hyt.it.ogt.kq.service.gov.model.vo.Tree;
import com.hyt.it.ogt.kq.service.gov.service.ITimeExaminerService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeService;
import com.hyt.it.ogt.kq.service.gov.service.TimeRoomExaminerCacheService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.hyt.it.ogt.kq.common.gov.enums.CacheKeyEnum.*;

/**
 * @author wuyingge
 * @version 1.0.0
 * @ClassName TimeRoomExaminerCacheServiceImpl.java
 * @Description 教务人员与批次，任务关系缓存
 * @createTime 2022年05月31日 17:23:00
 */
@Service
@Slf4j
public class TimeRoomExaminerCacheServiceImpl implements TimeRoomExaminerCacheService {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private TimeRoomExaminerMapper timeRoomExaminerMapper;

    @Resource
    private ITimeService iTimeService;

    @Resource
    private ITimeExaminerService iTimeExaminerService;

    /**
     * 查询监考员名下的考场数据
     */
    @Override
    public List<UserRoomVO> getUserRoomByProctorFromCache(String timeId, String taskId, String userId){
        try {
            String key = USER_TIME_CACHE_KEY.getCacheEnumKey(timeId,userId);
            String json = String.valueOf(redisTemplate.opsForValue().get(key));
            if(StringUtils.isBlank(json) || Objects.equals("null",json)){
                return putUserTimeCache(key, taskId, timeId, userId);
            }
            List<UserRoomVO> result = JSON.parseArray(json, UserRoomVO.class);
            return result;
        } catch (Exception e){
            log.error("教务人员与批次信息放入缓存，操作失败，异常为",e);
            throw new KqException(ResponseCode.ERROR_KS_USER_TYPE_NONE.getCode(),e);
        }
    }

    /**
     * 教务人员与批次信息放入缓存
     * @param key
     * @return
     */
    private List<UserRoomVO> putUserTimeCache(String key, String taskId, String timeId, String userId) {
        try {
            List<UserRoomVO> userRoomVOS = timeRoomExaminerMapper.selectUserRoomByProctor(taskId, timeId, userId);
            if(CollectionUtils.isEmpty(userRoomVOS)){
                return userRoomVOS;
            }
            String json = JSON.toJSONString(userRoomVOS);
            redisTemplate.opsForValue().set(key,json,USER_TIME_CACHE_KEY.getExpireSeconds(), TimeUnit.SECONDS);
            return userRoomVOS;
        } catch (Exception e){
            log.error("教务人员与批次信息放入缓存，操作失败，异常为",e);
            throw new KqException(ResponseCode.ERROR_KS_USER_TYPE_NONE.getCode(),e);
        }
    }

    /**
     * 查询监考员名下的批次数据
     * @param taskId
     * @return
     */
    @Override
    public List<UserTimeVO> getUserTimeByProctorFromCache(String taskId, String userId){
        try {
            String key = USER_TASK_CACHE_KEY.getCacheEnumKey(taskId,userId);
            String json = String.valueOf(redisTemplate.opsForValue().get(key));
            if(StringUtils.isBlank(json) || Objects.equals("null",json)){
                return putUserTaskCache(key,taskId,userId);
            }
            List<UserTimeVO> result = JSON.parseArray(json, UserTimeVO.class);
            return result;
        } catch (Exception e){
            log.error("查询监考员名下的批次数据放入缓存，操作失败，异常为",e);
            throw new KqException(ResponseCode.ERROR_KS_USER_TYPE_NONE.getCode(),e);
        }
    }

    /**
     * 考务人员与任务关系
     * @param key
     * @param taskId
     * @param userId
     * @return
     */
    private List<UserTimeVO> putUserTaskCache(String key, String taskId, String userId) {
        try {
            List<UserTimeVO> userRoomVOS = timeRoomExaminerMapper.selectUserTimeByProctor(taskId, userId);
            if(CollectionUtils.isEmpty(userRoomVOS)){
                return userRoomVOS;
            }
            String json = JSON.toJSONString(userRoomVOS);
            redisTemplate.opsForValue().set(key,json,USER_TASK_CACHE_KEY.getExpireSeconds(), TimeUnit.SECONDS);
            return userRoomVOS;
        } catch (Exception e){
            log.error("查询监考员名下的批次数据放入缓存，操作失败，异常为",e);
            throw new KqException(ResponseCode.ERROR_KS_USER_TYPE_NONE.getCode(),e);
        }
    }

    /**
     * 查询管理员名下的考场数据 -- 管理员
     * @param timeId
     * @return
     */
    @Override
    public List<UserRoomVO> getUserRoomByAdminFromCache(String timeId, String taskId){
        try {
            String key = USER_TIME_ADMIN_CACHE_KEY.getCacheEnumKey(timeId);
            String json = String.valueOf(redisTemplate.opsForValue().get(key));
            if(StringUtils.isBlank(json) || Objects.equals("null",json)){
                return putUserTimeAdminCache(key,timeId, taskId);
            }
            List<UserRoomVO> result = JSON.parseArray(json, UserRoomVO.class);
            return result;
        } catch (Exception e){
            log.error("教务人员与批次信息放入缓存，操作失败，异常为",e);
            throw new KqException(ResponseCode.ERROR_KS_USER_TYPE_NONE.getCode(),e);
        }
    }

    /**
     * 教务人员与批次信息放入缓存 -- 管理员
     * @param key
     * @return
     */
    private List<UserRoomVO> putUserTimeAdminCache(String key,String timeId, String taskId) {
        try {
            List<UserRoomVO> userRoomVOS = timeRoomExaminerMapper.selectUserRoomByAdmin(timeId, taskId);
            if(CollectionUtils.isEmpty(userRoomVOS)){
                return userRoomVOS;
            }
            String json = JSON.toJSONString(userRoomVOS);
            redisTemplate.opsForValue().set(key,json,USER_TIME_ADMIN_CACHE_KEY.getExpireSeconds(), TimeUnit.SECONDS);
            return userRoomVOS;
        } catch (Exception e){
            log.error("教务人员与批次信息放入缓存，操作失败，异常为",e);
            throw new KqException(ResponseCode.ERROR_KS_USER_TYPE_NONE.getCode(),e);
        }
    }

    private List<Tree> buildTree(List<UserRoomVO> list){
        List<Tree> treeList = new ArrayList<>();
        //先构造考点
        for(int i = 0 ; i < list.size(); i++){
            Tree tree = new Tree();
            tree.setId(list.get(i).getPlaceCode());
            tree.setText(list.get(i).getPlaceName());
            if(CollectionUtil.isEmpty(treeList)){
                treeList.add(tree);
            }else{
                boolean flag = true;
                for(int k = 0; k < treeList.size(); k++){
                    if(treeList.get(k).getId().equals(list.get(i).getPlaceCode())){
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    treeList.add(tree);
                }
            }
        }
        treeList.stream().forEach(c -> {
               List<Tree> childList = new ArrayList<>();
               list.stream().filter(d -> d.getPlaceCode().equals(c.getId())).forEach(e ->{
                           Tree tree = new Tree();
                           tree.setId(e.getRoomCode());
                           tree.setText(e.getRoomName());
                           tree.setPid(c.getId());
                           childList.add(tree);
               }
               );
               c.setChildren(childList);
         });


        return treeList;
    }

    /**
     * 清理任务下，批次下所有的考务人员的关联关系
     * @param timeId can be null
     * @param taskId not be null
     * @return
     */
    public Boolean clearUserProctorCache(String timeId,String taskId){
        log.info("开始清理批次下所有的考务人员的关联关系缓存");
        String timeAdminKey;
        List<String> timeUserKeys = new ArrayList<>();
        if(Objects.isNull(timeId)){
            List<Time> list = iTimeService.lambdaQuery().select(Time::getId)
                    .eq(Time::getTaskId, taskId)
                    .eq(Time::getDelFlag, false).list();
            List<String> timeIds = list.stream().map(Time::getId).collect(Collectors.toList());

            List<TimeExaminer> tes = new ArrayList<>();
            timeIds.forEach(t -> {
                tes.addAll(iTimeExaminerService.getByTime(taskId,t, UserRoleType.USER_ROLE_TYPE_PROCTOR.getCode(),null));
            });
            List<String> userIds = tes.stream().map(TimeExaminer::getUserId).collect(Collectors.toList());
            timeIds.forEach(t -> {
                String keyAdmin = USER_TIME_ADMIN_CACHE_KEY.getCacheEnumKey(t);
                timeUserKeys.add(keyAdmin);
                userIds.forEach(u -> {
                    String keyUser = USER_TIME_CACHE_KEY.getCacheEnumKey(t,u);
                    timeUserKeys.add(keyUser);
                });
            });
            userIds.forEach(u -> {
                String keyUser = USER_TASK_CACHE_KEY.getCacheEnumKey(taskId,u);
                timeUserKeys.add(keyUser);
            });
        } else {
            timeAdminKey = USER_TIME_ADMIN_CACHE_KEY.getCacheEnumKey(timeId);
            timeUserKeys.add(timeAdminKey);
            List<TimeExaminer> tes = iTimeExaminerService.getByTime(taskId,timeId, UserRoleType.USER_ROLE_TYPE_PROCTOR.getCode(),null);
            List<String> userIds = tes.stream().map(TimeExaminer::getUserId).collect(Collectors.toList());
            userIds.forEach(u -> {
                String keyUser = USER_TIME_CACHE_KEY.getCacheEnumKey(timeId,u);
                timeUserKeys.add(keyUser);
            });
            userIds.forEach(u -> {
                String keyUser = USER_TASK_CACHE_KEY.getCacheEnumKey(taskId,u);
                timeUserKeys.add(keyUser);
            });
        }

        try {
            log.info("开始清理批次下所有的考务人员的关联关系缓存,key:【{}】",timeUserKeys);
            redisTemplate.delete(timeUserKeys);
            return Boolean.TRUE;
        } catch (Exception e){
            log.error("清理考试任务与考务人员关联Redis缓存失败，传入的批次id：【{}】,任务id:【{}】",timeId,taskId,e);
            return Boolean.TRUE;
        }
    }
}
